package com.kwin.demo.server.framework.common.repeatsubmit.aspect;

import com.kwin.demo.server.framework.common.repeatsubmit.annotation.RepeatSubmit;
import com.kwin.demo.server.framework.common.lock.RedissLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Date;

/**
 * @author kwin
 * @Date 2022/1/16 15:17
 **/
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {

    private static final String REPEAT_LOCK_PREFIX = "repeatLock_";

    /**
     * 切点
     * @param repeatSubmit
     */
    @Pointcut("@annotation(repeatSubmit)")
    public void repeatPoint(RepeatSubmit repeatSubmit) {
    }

    /**
     *
     * @return
     */
    @Around(value = "repeatPoint(repeatSubmit)")
    public Object doAround(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) {
        String key = REPEAT_LOCK_PREFIX + repeatSubmit.location();

        String argName = repeatSubmit.argName();
        int argInx = repeatSubmit.argInx();
        Object[] args = joinPoint.getArgs();

        String suffix;
        if(!StringUtils.hasText(argName)) {
            suffix = String.valueOf(args[argInx]);
        } else {
            suffix = generateSuffix(args[argInx], argName);
        }

        key = key + ":" + suffix;
        if(!RedissLockUtil.tryLock(key, repeatSubmit.timeUnit(), 0, repeatSubmit.timeout())) {
            return "操作过于频繁，请稍后重试";
        }

        try {
            Object proceed = joinPoint.proceed();
            return proceed;
        } catch (Throwable throwable) {
            log.error("", throwable);
            throw new RuntimeException(throwable.getMessage());
        } finally {
            try {
                RedissLockUtil.unlock(key);
            } catch (Exception ex) {
                log.error("解锁失败，key is {}", key, ex);
            }

        }
    }


    public String generateSuffix(Object obj, String argName) {
        Class clzz = obj.getClass();
        Field argField = null;
        try {
            argField = clzz.getDeclaredField(argName);
            argField.setAccessible(Boolean.TRUE);
            Object arg = argField.get(obj);
            return String.valueOf(arg);
        } catch (NoSuchFieldException e) {
            log.error("no such field", e);
        } catch (IllegalAccessException e) {
            log.error("IllegalAccessException ", e);
        }
        return "SUFFIX";
    }
}
